#ifndef RENDERER_H
#define RENDERER_H

#include <iostream>
#include <GL/glew.h>
#include <GL/glfw.h>
#include "Export.h"
#include "Vector2.h"
#include "Vector3.h"
#include "Color3.h"
#include "Color4.h"

namespace glow
{
	class SHARED Renderer
	{
		public:

		//Parameters
		/**
         *  Initialise the Render's attributes with the parameters
		 *  \param near the near of the renderer
		 *  \param far the far of the renderer
		 *  \param fov the fov of the renderer
		 *  \param bgColor the color of the background
		 *  \param swapInterval the glfwSwapInterval
         **/
		void init(float near = 0.1f, float far = 10000.f, int fov = 75, Color3i bgColor = Color3i(255, 255, 255), int swapInterval = 1);
		
		
		/**
		 *  Resize the window
		 *\param width width of the window
		 *\param height height of the window
		 **/
		void resize(int width, int height);

		/**
		 *  Load opengl's extension
		 *\return true if the code is initialised, else false
		 **/
		bool initExtensions();
		
		/**
		 *  Check opengl's extension 
		 *\param name the extension to check
		 *\return true if the extension is supported, else false
		 **/
		bool checkExtension(const char *name);

		/**
		 *  Get the near of the render
		 *\return the near of the renderer
		 **/
		float getNear() const;
		
		/**
		 *  Get the far of the render
		 *\return the far of the renderer
		 **/
		float getFar() const;
		
		/**
		 *  Get the Fov of the renderer
		 *\return the fov of the renderer
		 **/
		int getFov() const;

		/**
		 *  Get the size of the window
		 *\return the size of the window
		 **/
		Vector2i getSize() const;
		
		/**
		 *  Get the background color of the window
		 *\return the color of the background
		 **/
		Color3i getBgColor() const;

		/**
		 * Set the viewport of the window
		 *\param minX the minimum value of the viewport's abscisse
		 *\param minY the minimum value of the viewport's ordonnate
		 *\param maxX the maximum value of the viewport's abscisse
		 *\param maxY the minimum value of the viewport's ordonnate
		 **/
		void setViewport(int minX, int minY, int maxX, int maxY);

		/**
		 *  Set the window in 2 dimensions
		 **/
        void set2DMode();
		
		/**
		 *  Stop the 2 dimension mode of the window
		 **/
        void end2DMode();

		/**
		 *  Set mode's parameter in the face's parameter
		 *\param face the face GLenum of glPolygonMode
		 *\param mode the mode GLenum of glPolygonMode
		 **/
        void setPolygonMode(GLenum face = GL_FRONT_AND_BACK, GLenum mode = GL_FILL);

        //Scene
		/**
		 *  Show the window
		 *\param cam the camera position
		 *\param target the position of the target
		 *\param axes the angle of the camera
		 **/
        void lookAt(Vector3d cam, Vector3d target = Vector3d(0, 0, 0), Vector3d axes = Vector3d(0, 1, 0));
        
		/**
		 *  Start to render the scene
		 *\param color the color of the scene
		 **/
		void beginScene(Color4f color = Color4f());
		
		/**
		 *  Clear the scene
		 **/
        void endScene();

        //Matrix
		/**
		 *  Set the matrix 
		 *\param mode the GLenum mode of the matrix
		 **/
        void setMatrix(GLenum mode);
		
		/**
		 *  Push the matrix
		 **/
        void pushMatrix();
		
		/**
		 *  Pop the matrix
		 **/
        void popMatrix();

        //Transformations
		/**
		 *  Set the scale
		 *\param scale the scale of the renderer
		 **/
        void scale(const Vector3d &scale);
		
		/**
		 *  Translate the 3-dimensions scene
		 *\param axes the axes of the renderer
		 **/
        void translate(const Vector3d &axes);
		
		/**
		 *  Rotate the scene
		 *\param angle the angle of rotate
		 *\param rot position of the rotate
		 **/
        void rotate(GLdouble angle, const Vector3d &rot);

		/**
		 *  Get Renderer's singleton instance
		 *\return the pointer to the current instance
		 **/
		static Renderer *getInstance();
		
		/**
		 *  Destroy the Renderer's singleton instance
		 **/
		static void destroy();

		private:

		Renderer();
		~Renderer();

        Vector2i _size;
		
        float _near;
		float _far;
        Color3i _bgColor;
        int _fov;
        static Renderer *_inst;
	};
}
#endif
